<template>
    <div class="claer" ref="clear" :style="{ width: clearWindow.width + 'px', height: clearWindow.height + 'px' }">
    </div>

    <!-- 操作按钮 -->
    <el-button style="margin: 10px;" type="success" @click="startSimulation()">开始仿真</el-button>
    <el-button style="margin: 10px;" type="danger" @click="stopSimulation()">暂停</el-button>
</template>

<script setup lang="ts">
import * as THREE from "three";
import { onMounted, reactive, ref } from "vue";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import * as TWEEN from "three/examples/jsm/libs/tween.module.js";
import { GUI, NumberController } from 'three/addons/libs/lil-gui.module.min.js';
import Stats from 'three/addons/libs/stats.module.js';
import { computed } from 'vue';


let clear = ref();
// 定义 canvas 窗口宽高
let clearWindow = reactive({
    width: 1000,
    height: 600
});
// let toolPosition = ref<THREE.Vector3>();
// 创建场景
const scene = new (THREE as any).Scene();
scene.background = new (THREE as any).Color(0xffffff);

//辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(100);
scene.add(axesHelper);


// 创建渲染器
const render = new THREE.WebGLRenderer({
    antialias: true,
    logarithmicDepthBuffer: true,
});
render.setSize(clearWindow.width, clearWindow.height);
render.setPixelRatio(window.devicePixelRatio);
render.setClearColor(0xffffff, 1);

// 添加性能监控
let stats;
stats = new Stats();
stats.dom.style.position = 'absolute';
stats.dom.style.top = '0';

// 创建相机
let cameraInfo = {
    position: {
        x: -200,
        y: 100,
        z: 200,
    },
};
const camera = new (THREE as any).PerspectiveCamera(45, clearWindow.width / clearWindow.height, 0.1, 1000);
const bestLength = 30;
camera.position.x = cameraInfo.position.x;
camera.position.y = cameraInfo.position.y;
camera.position.z = cameraInfo.position.z;
camera.lookAt(0, 0, 0);

// 轨道滑动器
const controls = new OrbitControls(camera, render.domElement); //轨道滑动器
controls.enableDamping = true;  // 设置带阻尼的惯性
controls.dampingFactor = 0.1; // 设置阻尼系数
controls.rotateSpeed = 0.14; // 旋转速度

// 创建灯光
const createLight = (x: number, y: number, z: number) => {
    const color = 0xffffff; //  灯光颜色
    const intensity = 1; // 灯光强度
    const light = new (THREE as any).DirectionalLight(color, intensity);
    light.position.set(x, y, z);
    light.target.position.set(0, 0, 0);
    return light;
};
const lights = [
    createLight(bestLength, bestLength, -bestLength),
    createLight(-bestLength, bestLength, -bestLength),
    createLight(-bestLength, bestLength, bestLength),
    createLight(-bestLength, -bestLength, bestLength),
    createLight(bestLength, -bestLength, -bestLength),
    createLight(-bestLength, -bestLength, -bestLength),
    createLight(-bestLength, -bestLength, bestLength),
    createLight(bestLength, -bestLength, bestLength),
];
lights.forEach((light) => scene.add(light));
lights.forEach((light) => scene.add(light.target));

///////////////////////////////////////////////////////////////

let workpiece: THREE.Mesh, tool: THREE.Mesh;
// 定义毛坯参数
let workpieceInfo = reactive({
    length: 100,
    width: 80,
    height: 25,
    // lengthSegments: 300,
    // widthSegments: 200,
    segmentDensity: 3, // 新增：每单位长度的分段数
    heightSegments: 1,
    wireframe: false,
});

const workpieceSegments = computed(() => {
    return {
        lengthSegments: Math.round(workpieceInfo.length * workpieceInfo.segmentDensity),
        widthSegments: Math.round(workpieceInfo.width * workpieceInfo.segmentDensity)
    };
});
// 定义刀具参数为独立变量
const toolRadius = 5; // 刀具半径 5mm
const toolHeight = 30;   // 刀具长度 22mm
let toolInfo = {
    toolRadius,
    toolHeight,
    // 刀具初始位置
    position: {
        x: -toolRadius - workpieceInfo.length / 2,
        y: workpieceInfo.height / 2 + toolHeight / 2,
        z: -toolRadius - workpieceInfo.width / 2,
    }
};
// 创建毛坯
function createWorkpiece(length: number, width: number, height: number, lengthSegments1: number = 100, widthSegments1: number = 100, heightSegments: number = 1) {
    const { lengthSegments, widthSegments } = workpieceSegments.value;
    const geometry = new THREE.BoxGeometry(length, height, width, lengthSegments, heightSegments, widthSegments);
    // geometry.translate(0, -height / 2, 0); 
    const material = new THREE.MeshLambertMaterial({
        color: 0xd3d3d3,
        // metalness: 0.2,
        // roughness: 0.8,
        wireframe: workpieceInfo.wireframe,
    });
    workpiece = new THREE.Mesh(geometry, material);
    // workpiece.position.set(length / 2, height / 2, width / 2);
    workpiece.position.set(0, 0, 0);
    workpiece.receiveShadow = true;
    workpiece.castShadow = true;
    scene.add(workpiece);
    return workpiece;
}

// 创建铣削刀具
function createTool(radius: number, height: number, position: THREE.Vector3) {
    const toolGeometry = new THREE.CylinderGeometry(radius, radius, height, 32);
    toolGeometry.translate(0, height / 2, 0); 
    const toolMaterial = new THREE.MeshStandardMaterial({
        color: 0x808080,
        // metalness: 0.9,
        // roughness: 0.2
        wireframe: true
    });
    const tool = new THREE.Mesh(toolGeometry, toolMaterial);
    // tool.position.set(0, 6, 0);
    tool.castShadow = true;

    // 设置刀具位置
    tool.position.copy(position);

    // 为刀具添加坐标系辅助对象
    const toolAxesHelper = new THREE.AxesHelper(20); // 2是坐标系的长度
    tool.add(toolAxesHelper); // 将坐标系添加到刀具对象中

    scene.add(tool);
    return tool;
}

interface pointPosition {
    x?: number;
    y?: number;
    z?: number;
}
let toolPathPoints: pointPosition[] = []; // 刀具路径
const depth = 0.5; // 切削深度
// 生成刀具路径
function generateToolPath() {
    // // 定义路径点
    toolPathPoints.push({ x: toolInfo.position.x, y: toolInfo.position.y - depth, z: toolInfo.position.z });    // 刀具下降
    toolPathPoints.push({ x: toolInfo.position.x + 2 * toolInfo.toolRadius, y: toolInfo.position.y - depth, z: toolInfo.position.z + 2 * toolInfo.toolRadius });    // 刀具右移
    toolPathPoints.push({ x: toolInfo.position.x + 2 * toolInfo.toolRadius, y: toolInfo.position.y - depth, z: toolInfo.toolRadius + workpieceInfo.width / 2 });
    toolPathPoints.push({ y: toolInfo.position.y });    // 刀具上升
    toolPathPoints.push({ x: toolInfo.position.x, y: toolInfo.position.y, z: toolInfo.position.z });    // 返回到初始位置
}

// 创建路径可视化
let pathVisualization = new THREE.Line();


const createPathVisualization = (toolPathPoints: pointPosition[]) => {
    let lastPoint = new THREE.Vector3(0, 0, 0);
    const points: THREE.Vector3[] = [];

    toolPathPoints.forEach(p => {
        const x = p.x !== undefined ? p.x : lastPoint.x;
        const y = p.y !== undefined ? p.y : lastPoint.y;
        const z = p.z !== undefined ? p.z : lastPoint.z;
        
        const currentPoint = new THREE.Vector3(x, y, z);
        points.push(currentPoint);
        lastPoint = currentPoint; 
    });

    const geometry = new THREE.BufferGeometry().setFromPoints(points);

    const material = new THREE.LineBasicMaterial({
        color: 0x00FF00,
        transparent: true,
        opacity: 0.5
    });

    pathVisualization.geometry = geometry;
    pathVisualization.material = material;
    scene.add(pathVisualization);
};

let nowCube: THREE.Mesh;
// 添加模型和刀具到场景中
const addModelAndTool = async () => {
    // 创建毛坯
    createWorkpiece(workpieceInfo.length,
        workpieceInfo.width,
        workpieceInfo.height,
        workpieceInfo.lengthSegments,
        workpieceInfo.widthSegments,
        workpieceInfo.heightSegments
    );
    // 创建铣削刀具
    tool = createTool(toolRadius,
        toolInfo.toolHeight,
        new THREE.Vector3(toolInfo.position.x, toolInfo.position.y, toolInfo.position.z)
    );
    // tool = createTool(toolRadius, toolHeight, new THREE.Vector3(toolRadius, 10 - depth, toolRadius + workpieceInfo.width));// mock铣削刀具位置
    nowCube = workpiece;
};

let index = 0
let isAnimating = ref<boolean>(false)
let animationTime: number[] = [1000, 1000, 5000, 1000, 1000]

const animateLoop = async () => {
    if (!isAnimating.value) {
        return;
    }
    if (index >= toolPathPoints.length) {
        isAnimating.value = false;
        return;
    }
    scene.remove(nowCube);
    const pos = toolPathPoints[index];
    new TWEEN.Tween(tool.position)
        .to({ x: pos.x, y: pos.y, z: pos.z }, animationTime[index])
        .onUpdate(() => {
            if (processWorkpieceCut(nowCube, tool)) {
                scene.remove(nowCube);
                scene.add(nowCube); // 刷新显示
            } else {
                scene.add(nowCube);
            }
        })
        .onComplete(() => {
            index++;
            animateLoop();
        })
        .start();
};
// 切削算法
function processWorkpieceCut(workpiece: THREE.Mesh, tool: THREE.Mesh): boolean {
    // 1. 碰撞检测（包围盒）
    const workpieceBox = new THREE.Box3().setFromObject(workpiece);
    const toolBox = new THREE.Box3().setFromObject(tool);
    const hasCollision = workpieceBox.intersectsBox(toolBox);

    if (!hasCollision) return false;

    // 2. 转换刀具位置到工件局部坐标系
    const toolLocalPos = workpiece.worldToLocal(tool.position.clone());
    
    // 3. 计算工件底面高度
    const workpieceBottom = -workpieceInfo.height / 2; // 工件底面在局部坐标系中的Y值

    // 4. 获取几何数据
    const geometry = workpiece.geometry as THREE.BufferGeometry;
    const positionAttr = geometry.getAttribute('position');
    const toolBottomY = toolLocalPos.y ; // 刀具底部高度
    
    // 5. 判断是否贯通切削
    const isThroughCut = toolBottomY <= workpieceBottom;
    let isCut = false;

    // 6. 遍历顶点处理
    for (let i = 0; i < positionAttr.count; i++) {
        const vertex = new THREE.Vector3().fromBufferAttribute(positionAttr, i);

        // 计算xz平面距离
        const dx = vertex.x - toolLocalPos.x;
        const dz = vertex.z - toolLocalPos.z;
        const distanceSq = dx * dx + dz * dz;

        // 判断是否在切割范围内
        const currentToolRadius = toolInfo.toolRadius;
        if (distanceSq <= currentToolRadius * currentToolRadius) {
            let newHeight = vertex.y;
            
            if (isThroughCut) {
                // 贯通切削：直接将顶点压到工件底面以下
                newHeight = workpieceBottom - 0.1; // 低于底面形成通孔
            } else if (vertex.y > toolBottomY) {
                // 非贯通切削：仅降低到刀具底部高度
                newHeight = Math.max(toolBottomY, workpieceBottom);
            }
            
            // 更新顶点高度
            if (vertex.y !== newHeight) {
                positionAttr.setXYZ(i, vertex.x, newHeight, vertex.z);
                isCut = true;
            }
        }
    }

    // 7. 刷新网格
    if (isCut) {
        positionAttr.needsUpdate = true;
        geometry.computeVertexNormals();
        geometry.computeBoundingBox();
        geometry.computeBoundingSphere();
    }

    return isCut;
}

// 在 createGui 中显式保存控制器
let xController: NumberController<THREE.Vector3, "x">, yController: NumberController<THREE.Vector3, "y">, zController: NumberController<THREE.Vector3, "z">;

function createGui(mesh: THREE.Mesh) {
    const gui = new GUI();
    const toolInfoFolder = gui.addFolder('刀具信息');
    const toolPositionFolder = toolInfoFolder.addFolder('刀具坐标');

    xController = toolPositionFolder.add(mesh.position, 'x', -60, 60).name('刀具x坐标');
    yController = toolPositionFolder.add(mesh.position, 'y', -24, 24).name('刀具y坐标');
    zController = toolPositionFolder.add(mesh.position, 'z', -45, 45).name('刀具z坐标');

    // 为每个控制器绑定更新逻辑
    [xController, yController, zController].forEach(controller => {
        controller.onChange(() => {
            if (processWorkpieceCut(nowCube, tool)) {
                scene.remove(nowCube);
                scene.add(nowCube);
            } else {
                scene.add(nowCube);
            }
        });
    });
    toolInfoFolder.add(toolInfo, 'toolRadius', 3, 5).name('刀具半径').onChange((value) => {
        updateToolWithNewRadius(value);
        if (processWorkpieceCut(nowCube, tool)) {
            scene.remove(nowCube);
            scene.add(nowCube);
        } else {
            scene.add(nowCube);
        }
    });

    // 工件设置文件夹
    const workpieceFolder = gui.addFolder('工件设置');
    workpieceFolder
        .add(workpieceInfo, 'wireframe')
        .name('线框模式')
        .onChange((value: boolean) => {
            if (workpiece && workpiece.material) {
                const material = workpiece.material as THREE.MeshLambertMaterial;
                material.wireframe = value;
                material.needsUpdate = true; // 确保材质更新生效
            }
        });

    const segmentsFolder = workpieceFolder.addFolder('分段数');

    // 添加分段数控制器
    segmentsFolder
        .add(workpieceInfo, 'segmentDensity', 1, 5)
        .name('分段密度 (单位长度)')
        .onChange(() => updateWorkpieceGeometry());
    
    segmentsFolder
        .add(workpieceInfo, 'heightSegments', 1, 3)
        .name('高度分段数')
        .onChange(() => updateWorkpieceGeometry());
    
    // 添加只读显示
    // segmentsFolder.add({ 
    //     lengthSegments: workpieceSegments.value.lengthSegments 
    // }, 'lengthSegments').name('长度分段数').listen();
    
    // segmentsFolder.add({ 
    //     widthSegments: workpieceSegments.value.widthSegments 
    // }, 'widthSegments').name('宽度分段数').listen();
}

function updateToolWithNewRadius(value: number) {
    const oldPosition = tool.position.clone();

    // 1. 清理旧刀具
    scene.remove(tool);
    tool.geometry.dispose();

    // 2. 更新配置并创建新刀具
    toolInfo.toolRadius = value;
    tool = createTool(toolInfo.toolRadius, toolInfo.toolHeight, oldPosition);
    scene.add(tool);

    // 3. 重新绑定控制器到新刀具
    [xController, yController, zController].forEach(controller => {
        controller.object = tool.position; // 更新控制器绑定的对象
    });
}

function updateWorkpieceGeometry() {
    if (!workpiece) return;
    
    const { lengthSegments, widthSegments } = workpieceSegments.value;
    
    // 更新几何体参数
    const geometry = new THREE.BoxGeometry(
        workpieceInfo.length,
        workpieceInfo.height,
        workpieceInfo.width,
        lengthSegments,
        workpieceInfo.heightSegments,
        widthSegments
    );
    
    // 替换几何体
    workpiece.geometry.dispose();
    workpiece.geometry = geometry;
    
    // 更新法线和包围盒
    geometry.computeVertexNormals();
    geometry.computeBoundingBox();
    geometry.computeBoundingSphere();
    
    // 标记需要更新
    geometry.attributes.position.needsUpdate = true;
}
// 点击按钮开始仿真 布尔运算
function startSimulation() {
    isAnimating.value = true
    if (isAnimating.value) {
        animateLoop();
    }
}

// 修改后的暂停方法
function stopSimulation() {
    isAnimating.value = false;
    index = 0; // 重置动画索引
    (TWEEN as any).removeAll(); // 强制移除所有tween动画
    console.log('动画已暂停');
}

//  渲染函数
const animate = () => {
    controls.update(); // 轨道滑动器更新
    stats.update();
    requestAnimationFrame(animate); // 递归调用
    render.render(scene, camera); // 渲染
    (TWEEN as any).update(); // 更新动画
    // 打印相机位置
    // console.log(camera.position)
};


// 挂载
onMounted(() => {
    clear.value.appendChild(render.domElement);
    clear.value.appendChild(stats.dom);
    animate();
    //////////////////////////
    addModelAndTool();// 添加模型和刀具
    generateToolPath();// 生成刀具路径
    createGui(tool);
    createPathVisualization(toolPathPoints);
    //////////////////////////
});
</script>

<style lang="less">
.claer {
    border: 1px solid #ccc;
    margin: 10px;
}
</style>